/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 *
 */

import process from 'process';

import { noop } from '../../../../common/util/noop.js';
import { CoreTaskImpl } from '../../../external/task/core-task-impl.js';
import { wrapIncrementalDeclarations } from '../../../incremental-decorator/wrap.js';
import { HvigorLogger } from '../../../log/hvigor-log.js';
import { isIncrementalTask } from '../../../util/task-util.js';
import { formatTime, formatTimeToNumber } from '../../../util/time-util.js';
import { doIncrementalTask } from '../../core/incremental-task-executor.js';
import { HVIGOR_PROCESS_EVENT_ID } from '../../lifecycle/event/event-id-options.js';
import { hvigorProcess } from '../../lifecycle/hvigor-process.js';
import { getModuleFromTaskPath } from '../util/task-module-util.js';
import { getTaskNameFromTaskPath } from '../util/task-path-util.js';
import { onTaskDisabled, onTaskFailed, onTaskFinished, onTaskUpToDated, onWorkFailed } from './listener/task-control-center-listener.js';
import { taskControlCenter } from './task-control-center.js';
import { TASK_EXECUTE_STATUS } from './task-execute-status.js';
import { IncrementalTask } from '../../../external/task/incremental-task.js';
import { hvigorCore } from '../../../external/core/hvigor-core.js';
import { INCREMENTAL_OPTIMIZATION } from '../../../../common/const/const.js';

const _log = HvigorLogger.getLogger('task-runner');

export const runTaskFromQueue = async () => {
  const curTask =
    hvigorCore.getParameter().getProperty(INCREMENTAL_OPTIMIZATION) === true
      ? getPriorTask() || taskControlCenter.popRunnableTask()
      : taskControlCenter.popRunnableTask();

  if (!curTask) {
    if (taskControlCenter.allTasksHasExecuted()) {
      // 发送整个任务执行完毕的事件
      hvigorProcess.emit(HVIGOR_PROCESS_EVENT_ID.FINISHED);
    }
    return;
  }
  const module = getModuleFromTaskPath(curTask);
  if (!module) {
    // 发送失败的事件, 找不到任务所属模块
    const error = `Cannot find module from task ${curTask}!`;
    _log.error(error);
    hvigorProcess.emit(HVIGOR_PROCESS_EVENT_ID.FAILED, error);
    return;
  }
  const taskName: string = getTaskNameFromTaskPath(curTask);
  const task = module.getTaskContainer().findTask(taskName) as CoreTaskImpl;
  if (task === undefined) {
    // 发送失败的事件, 找不到任务实例
    const error = `Cannot find task ${curTask}!`;
    _log.error(error);
    hvigorProcess.emit(HVIGOR_PROCESS_EVENT_ID.FAILED, error);
    return;
  }
  hvigorProcess.hasTaskDone = true;

  // 设置task就绪
  task.taskExecutedStatus.setState(TASK_EXECUTE_STATUS.PENDING);
  const isSucceed = await executeOneTask(task);
  if (!isSucceed) {
    return;
  }
  const hasPendingPromises = !!task.pendingPromises.get().length;

  if (!task.getEnabled()) {
    onTaskDisabled(task);
  } else if (task.taskExecutedStatus.isUpToDate()) {
    onTaskUpToDated(task);
  } else if (!hasPendingPromises) {
    const taskEndTime: [number, number] = process.hrtime(hvigorProcess.taskBeginTime);
    const realTime = formatTime(taskEndTime);
    _log.debug(`runTaskFromQueue task cost before running: ${realTime}`);

    // 执行task afterRun队列
    await task.executeAfterRun?.bind(task)();
    onTaskFinished(task);
  }
  if (hasPendingPromises) {
    handleTaskPendingPromises(task);
  }
  await runTaskFromQueue();
};

const handleTaskPendingPromises = (task: CoreTaskImpl) => {
  const promises = task.pendingPromises.get();
  task.pendingPromises.clear();

  // 失败
  promises.forEach((promise) => {
    promise.catch((e) => {
      onWorkFailed(task, e);
    });
  });

  // 成功
  Promise.all(promises)
    .catch(() => {
      // 异常已在上面处理
      return Promise.reject('failed');
    })
    .then(async () => {
      // 执行task afterRun队列
      await task.executeAfterRun?.bind(task)();
      onTaskFinished(task);
      return runTaskFromQueue();
    })
    .catch((e) => {
      if (e instanceof Error) {
        hvigorProcess.error(e);
      }
    });
};

/**
 * 获取需要优先执行的任务
 */
function getPriorTask(): string | undefined {
  let priorTask;
  const arrayTask = hvigorCore.getCompileDependArr();
  for (let arr of arrayTask) {
    priorTask = taskControlCenter.remove(arr);
    if (priorTask) {
      break;
    }
  }
  return priorTask;
}

async function executeOneTask(coreTask: CoreTaskImpl): Promise<boolean> {
  try {
    const startHeapUse = process.memoryUsage();

    // 改变Task状态为正在执行
    coreTask.taskExecutedStatus.setState(TASK_EXECUTE_STATUS.RUNNING);
    coreTask.durationEvent.start();

    // 将task设置到阻塞队列中
    taskControlCenter.pushRunningTask(coreTask);

    if (!coreTask.getEnabled()) {
      coreTask.taskExecutedStatus.setState(TASK_EXECUTE_STATUS.END);
      return true;
    }

    _log.debug(`Executing task :${coreTask.getPath()}`);
    if (coreTask instanceof IncrementalTask) {
      await coreTask.beforeAlwaysAction();
      wrapIncrementalDeclarations(coreTask);
    }
    if (isIncrementalTask(coreTask)) {
      await doIncrementalTask(coreTask);
    } else {
      // 执行task的taskAction
      await coreTask.execute();
    }
    coreTask.taskExecutedStatus.setState(TASK_EXECUTE_STATUS.END);
    const endHeapUse = process.memoryUsage();
    _log.debug(coreTask.getNode().getName(), ':', coreTask.getName(), 'cost memory', (endHeapUse.heapUsed - startHeapUse.heapUsed) / 1024 / 1024);
    const beginTime = formatTimeToNumber(coreTask.taskExecutedStatus.getTaskBeginTime());
    coreTask.taskExecutedStatus.setWorkerTimePeriod([beginTime, Number(process.hrtime.bigint())]);
    return true;
  } catch (e: unknown) {
    if (e instanceof Error) {
      onTaskFailed(coreTask, e);
      hvigorProcess.error(e, coreTask.getTaskLog());
      return false;
    }

    return true;
  }
}
